#!/usr/bin/perl -wc

package RFCMail::ESMTP::Server;

use strict;
use warnings;
use base qw(RFCMail::Common::Layered);
use RFCMail::Common::Grammar qw(gen_id);


sub import {
    my $class = shift;
    $class->SUPER::import('RFCMail::ESMTP::Common', @_);
}


sub data_start {
    my $self = shift;
    $self->{state}->{trans_id} = gen_id();
    return ($self->SUPER::data_start(@_));
}


sub data_abort {
    my $self = shift;
    $self->SUPER::data_abort(@_);
    delete($self->{state}->{trans_id});
}


sub data_commit {
    my $self = shift;
    $self->SUPER::data_commit(@_);
    # buffers cleared in accordance with RFC 2821 4.1.1.4
    $self->reset;
}



package RFCMail::ESMTP::Server::base;

use strict;
use warnings;
use RFCMail::Util::NetEnd;
use RFCMail::ESMTP::Server::Base::Commands;
use RFCMail::ESMTP::Server::Base::Data;
use RFCMail::ESMTP::Server::Base::IO;
use RFCMail::ESMTP::Server::Base::Logging;
use RFCMail::ESMTP::Server::Base::Modes;
use RFCMail::ESMTP::Server::Base::Policy;
use RFCMail::ESMTP::Server::Parser;
use RFCMail::ESMTP::Server::State;


sub init {
    my $self = shift;
    $self->{timeout} = 300
	if not defined($self->{timeout});
    $self->{state} = RFCMail::ESMTP::Server::State->new
        if not defined($self->{state});
    $self->{handlers} = RFCMail::ESMTP::Server::Parser->new_standard
	if not defined($self->{handlers});
    $self->{greeting} = "ESMTP Server ready for ".$self->peer_address_literal("non-inet session")
        if not defined($self->{greeting});
}


sub session {
    my ($self) = @_;
    my ($rcode, $mode_method);
    my $peer = $self->peer_address_literal("non-inet client");
    $self->logmsg(n => "commencing session with $peer");
    $self->{mode} = 'command_mode';
    my ($connect) = $self->{handlers}->parse_cmd("_");
    $rcode = $self->reply($self->$connect);
    while ($rcode !~ /^.21/) {
	$mode_method = $self->{mode};
	$rcode = $self->$mode_method;
    }
    $self->logmsg(n => "session with $peer ends");
    return ($rcode);
}


sub select_reply {
    my ($self, @argv) = @_;
    while (defined($argv[1])) {
	@argv[0,1] = @argv[1,0]
	    if $argv[0][0] > $argv[1][0];
	shift @argv;
    }
    return ($argv[0]);
}


sub reset { $_[0]->{state}->reset }


sub peer_address_literal {
    my ($self, $alt) = @_;
    my $peer_ip = $self->{peer_end}->address;
    return ($peer_ip ? "[$peer_ip]" : $alt);
}


sub cleanup {}


1;
